# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

# -*- coding: utf-8 -*-
"""
测试 any 类型（弱类型）与强类型之间的转换
"""

from tests.pytests.helpers.codegen_helpers import compile_chunk, assert_code_contains
from typing import Any


def test_strong_to_any_assignment():
    """测试强类型 -> any 的赋值（隐式构造）"""

    def test_int_to_any() -> Any:
        """int -> any 转换"""
        x: int = 42
        y: Any = x  # 隐式构造
        return y

    cpp = compile_chunk(test_int_to_any)
    expected = """
    mc::variant test_int_to_any() {
        int x = 42;
        mc::variant y = x;
        return y;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_to_int_assignment():
    """测试 any -> int 的赋值（显式转换）"""

    def test_any_to_int() -> int:
        """any -> int 转换"""
        x: Any = 42
        y: int = x
        return y

    cpp = compile_chunk(test_any_to_int)
    expected = """
    int test_any_to_int() {
        mc::variant x = 42;
        int y = mcpy::cast<int>(x);
        return y;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_to_string_assignment():
    """测试 any -> string 的赋值"""

    def test_any_to_str() -> str:
        """any -> str 转换"""
        x: Any = "hello"
        y: str = x
        return y

    cpp = compile_chunk(test_any_to_str)
    expected = """
    std::string test_any_to_str() {
        mc::variant x = "hello";
        std::string y = mcpy::cast<std::string>(x);
        return y;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_to_dict_assignment():
    """测试 any -> dict 的赋值"""

    def test_any_to_dict(data: dict) -> dict:
        """dict 索引返回 any，需要转换回 dict"""
        item: Any = data["key"]
        result: dict = item
        return result

    cpp = compile_chunk(test_any_to_dict)
    expected = """
    mc::dict test_any_to_dict(const mc::dict& data) {
        mc::variant item = data["key"];
        mc::dict result = mcpy::cast<mc::dict>(item);
        return result;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_to_any_assignment():
    """测试 any -> any 的赋值（无需转换）"""

    def test_any_to_any() -> Any:
        """any -> any 无需转换"""
        x: Any = 42
        y: Any = x
        return y

    cpp = compile_chunk(test_any_to_any)
    expected = """
    mc::variant test_any_to_any() {
        mc::variant x = 42;
        mc::variant y = x;
        return y;
    }
    """
    assert_code_contains(cpp, expected)
    # 验证没有类型转换
    assert "cast" not in cpp


def test_any_arithmetic_operations():
    """测试 any 类型的算术运算（利用 variant 运算符重载）"""

    def test_any_add() -> int:
        """any + any 算术运算"""
        x: Any = 10
        y: Any = 20
        result: int = x + y
        return result

    cpp = compile_chunk(test_any_add)
    expected = """
    int test_any_add() {
        mc::variant x = 10;
        mc::variant y = 20;
        int result = mcpy::cast<int>(x + y);
        return result;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_mixed_arithmetic():
    """测试 any 与强类型的混合运算"""

    def test_mixed_add() -> int:
        """any + int 混合运算"""
        x: Any = 10
        y: int = 5
        result: int = x + y  # variant + int
        return result

    cpp = compile_chunk(test_mixed_add)
    expected = """
    int test_mixed_add() {
        mc::variant x = 10;
        int y = 5;
        int result = mcpy::cast<int>(x + y);
        return result;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_comparison_operations():
    """测试 any 与强类型的比较运算"""

    def test_any_compare() -> bool:
        """any 比较运算"""
        x: Any = 42
        return x == 42  # variant 重载的 operator==

    cpp = compile_chunk(test_any_compare)
    expected = """
    bool test_any_compare() {
        mc::variant x = 42;
        return x == 42;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_function_parameter():
    """测试 any 作为强类型函数参数（需要转换）"""

    code = """
from typing import Any

def process_int(value: int) -> int:
    return value + 1

def test_any_param() -> int:
    x: Any = 42
    return process_int(x)
"""

    cpp = compile_chunk(code)
    expected = """
    int process_int(int value) {
        return value + 1;
    }
    int test_any_param() {
        mc::variant x = 42;
        return process_int(mcpy::cast<int>(x));
    }
    """
    assert_code_contains(cpp, expected)


def test_any_return_value_conversion():
    """测试函数返回 any 类型并转换为强类型"""

    code = """
from typing import Any

def get_any_value() -> Any:
    return 42

def test_any_return() -> int:
    x: Any = get_any_value()
    return x
"""

    cpp = compile_chunk(code)
    expected = """
    mc::variant get_any_value() {
        return 42;
    }
    int test_any_return() {
        mc::variant x = get_any_value();
        return mcpy::cast<int>(x);
    }
    """
    assert_code_contains(cpp, expected)


def test_dict_subscript_returns_any():
    """测试 dict 下标访问返回 any 类型"""

    def test_dict_access() -> int:
        """dict 访问返回 variant"""
        data: dict = {"port": 8080}
        port: int = data["port"]  # dict["key"] 返回 variant
        return port

    cpp = compile_chunk(test_dict_access)
    expected = """
    int test_dict_access() {
        mc::dict data = mc::dict{{"port", 8080}};
        int port = mcpy::cast<int>(data["port"]);
        return port;
    }
    """
    assert_code_contains(cpp, expected)


def test_dict_nested_access():
    """测试嵌套 dict 访问（链式访问）"""

    def test_nested_dict() -> int:
        """嵌套 dict 访问"""
        d: dict = {"a": {"b": {"c": 100}}}
        result: int = d["a"]["b"]["c"]
        return result

    cpp = compile_chunk(test_nested_dict)
    expected = """
    int test_nested_dict() {
        mc::dict d = mc::dict{{"a", mc::dict{{"b", mc::dict{{"c", 100}}}}}};
        int result = mcpy::cast<int>(d["a"]["b"]["c"]);
        return result;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_with_multiple_conversions():
    """测试多次 any 类型转换"""

    def test_multiple_conversions() -> int:
        """多次类型转换"""
        x: int = 42
        y: Any = x  # int -> any
        z: int = y  # any -> int
        w: Any = z  # int -> any
        result: int = w  # any -> int
        return result

    cpp = compile_chunk(test_multiple_conversions)
    expected = """
    int test_multiple_conversions() {
        int x = 42;
        mc::variant y = x;
        int z = mcpy::cast<int>(y);
        mc::variant w = z;
        int result = mcpy::cast<int>(w);
        return result;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_in_container():
    """测试容器中的 any 类型元素"""

    def test_any_list() -> int:
        """list[Any] 元素访问"""
        items: list[Any] = [1, 2, 3]
        x: int = items[0]  # list[any] 索引返回 any
        return x

    cpp = compile_chunk(test_any_list)
    expected = """
    int test_any_list() {
        mc::variants items = {1, 2, 3};
        int x = mcpy::cast<int>(mcpy::list_getitem(items, 0));
        return x;
    }
    """
    assert_code_contains(cpp, expected)


def test_weak_type_dict():
    """测试弱类型 dict（不带类型参数）"""

    def test_weak_dict() -> int:
        """弱类型 dict 访问"""
        d: dict = {"x": 10, "y": 20}
        result: int = d["x"] + d["y"]
        return result

    cpp = compile_chunk(test_weak_dict)
    expected = """
    int test_weak_dict() {
        mc::dict d = mc::dict{{"x", 10}, {"y", 20}};
        int result = mcpy::cast<int>(d["x"] + d["y"]);
        return result;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_bool_conversion():
    """测试 any -> bool 转换"""

    def test_any_to_bool() -> bool:
        """any -> bool 转换"""
        x: Any = True
        y: bool = x
        return y

    cpp = compile_chunk(test_any_to_bool)
    expected = """
    bool test_any_to_bool() {
        mc::variant x = true;
        bool y = mcpy::cast<bool>(x);
        return y;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_float_conversion():
    """测试 any -> float 转换"""

    def test_any_to_float() -> float:
        """any -> float 转换"""
        x: Any = 3.14
        y: float = x
        return y

    cpp = compile_chunk(test_any_to_float)
    expected = """
    double test_any_to_float() {
        mc::variant x = 3.14;
        double y = mcpy::cast<double>(x);
        return y;
    }
    """
    assert_code_contains(cpp, expected)


def test_function_chain_with_any():
    """测试函数调用链（验证不会过度转换）"""

    code = """
def accept_int(x: int) -> int:
    return x + 1

def test_chain() -> int:
    d: dict = {"a": {"b": {"c": 100}}}
    result: int = accept_int(d["a"]["b"]["c"])
    return result
"""

    cpp = compile_chunk(code)
    expected = """
    int accept_int(int x) {
        return x + 1;
    }
    int test_chain() {
        mc::dict d = mc::dict{{"a", mc::dict{{"b", mc::dict{{"c", 100}}}}}};
        int result = accept_int(mcpy::cast<int>(d["a"]["b"]["c"]));
        return result;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_expression_chain():
    """测试 any 类型的链式表达式"""

    def test_chain_expr() -> int:
        """链式表达式"""
        x: Any = 100
        y: Any = 20
        temp: Any = x - y
        result: int = temp + 5
        return result

    cpp = compile_chunk(test_chain_expr)
    expected = """
    int test_chain_expr() {
        mc::variant x = 100;
        mc::variant y = 20;
        mc::variant temp = x - y;
        int result = mcpy::cast<int>(temp + 5);
        return result;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_with_comparison():
    """测试 any 类型的比较表达式"""

    def test_compare() -> bool:
        """比较表达式"""
        x: Any = 10
        return x > 5 and x < 100

    cpp = compile_chunk(test_compare)
    expected = """
    bool test_compare() {
        mc::variant x = 10;
        return x > 5 && x < 100;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_complex_scenario():
    """测试复杂场景：混合 any、dict、运算"""

    def test_complex() -> int:
        """复杂的混合场景"""
        x: Any = 10
        y: Any = 20
        d: dict = {"factor": 2}
        sum_val: Any = x + y
        factor: int = d["factor"]
        result: int = sum_val * factor
        return result

    cpp = compile_chunk(test_complex)
    expected = """
    int test_complex() {
        mc::variant x = 10;
        mc::variant y = 20;
        mc::dict d = mc::dict{{"factor", 2}};
        mc::variant sum_val = x + y;
        int factor = mcpy::cast<int>(d["factor"]);
        int result = mcpy::cast<int>(sum_val * factor);
        return result;
    }
    """
    assert_code_contains(cpp, expected)


# ============================================================================
# 位运算符测试
# ============================================================================


def test_any_bitwise_operations():
    """测试 any 类型的位运算符"""

    def test_bitwise() -> int:
        """位运算测试"""
        x: Any = 12
        y: Any = 10
        result1: int = x & y  # 按位与
        result2: int = x | y  # 按位或
        result3: int = x ^ y  # 按位异或
        return result1 + result2 + result3

    cpp = compile_chunk(test_bitwise)
    expected = """
    int test_bitwise() {
        mc::variant x = 12;
        mc::variant y = 10;
        int result1 = mcpy::cast<int>(x & y);
        int result2 = mcpy::cast<int>(x | y);
        int result3 = mcpy::cast<int>(x ^ y);
        return result1 + result2 + result3;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_shift_operations():
    """测试 any 类型的移位运算符"""

    def test_shift() -> int:
        """移位运算测试"""
        x: Any = 5
        left_shift: int = x << 2  # any << int
        right_shift: int = left_shift >> 1  # int >> int
        return right_shift

    cpp = compile_chunk(test_shift)
    expected = """
    int test_shift() {
        mc::variant x = 5;
        int left_shift = mcpy::cast<int>(x << 2);
        int right_shift = left_shift >> 1;
        return right_shift;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_shift_any_as_right():
    """测试 any 作为右操作数的移位运算"""

    def test_shift_right() -> int:
        """any 在右侧的移位"""
        x: int = 5
        y: Any = 2
        result: int = x << y  # int << any
        return result

    cpp = compile_chunk(test_shift_right)
    expected = """
    int test_shift_right() {
        int x = 5;
        mc::variant y = 2;
        int result = mcpy::cast<int>(x << y);
        return result;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_all_comparison_operators():
    """测试 any 类型的所有比较运算符"""

    def test_all_compare() -> bool:
        """所有比较运算符"""
        x: Any = 42
        y: Any = 42
        z: Any = 40
        return x == y and x != z and x > z and x >= y and z < x and z <= y

    cpp = compile_chunk(test_all_compare)
    expected = """
    bool test_all_compare() {
        mc::variant x = 42;
        mc::variant y = 42;
        mc::variant z = 40;
        return x == y && x != z && x > z && x >= y && z < x && z <= y;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_modulo_operation():
    """测试 any 类型的取模运算"""

    def test_modulo() -> int:
        """取模运算"""
        x: Any = 17
        y: Any = 5
        result: int = x % y
        return result

    cpp = compile_chunk(test_modulo)
    expected = """
    int test_modulo() {
        mc::variant x = 17;
        mc::variant y = 5;
        int result = mcpy::cast<int>(x % y);
        return result;
    }
    """
    assert_code_contains(cpp, expected)


def test_any_list_extend():
    """测试 any 作为 list.extend 的参数（需要转换）"""

    code = """
from typing import Any

def test_any_list_extend() -> int:
    items: list[Any] = [1, 2]
    items.extend([3, 4, 5])
    return len(items)
"""

    cpp = compile_chunk(code)
    expected = """
    int test_any_list_extend() {
        mc::variants items = {1, 2};
        mcpy::list_extend(items, {3, 4, 5});
        return items.size();
    }
    """
    assert_code_contains(cpp, expected)


# ============================================================================
# Set 与 Any 类型交互测试
# ============================================================================


def test_set_any_creation():
    """测试 set[Any] 的创建"""

    def test_creation() -> int:
        """创建 set[Any]"""
        items: set[Any] = {1, "hello", 3.14}
        return len(items)

    cpp = compile_chunk(test_creation)
    expected = """
    int test_creation() {
        mcpy::variant_set items = {1, "hello", 3.14};
        return items.size();
    }
    """
    assert_code_contains(cpp, expected)


def test_set_any_operations():
    """测试 set[Any] 的基本操作"""

    def test_ops() -> int:
        """set[Any] 操作"""
        s: set[Any] = {1, 2, 3}
        s.add(4)
        s.add("hello")
        s.remove(2)
        return len(s)

    cpp = compile_chunk(test_ops)
    expected = """
    int test_ops() {
        mcpy::variant_set s = {1, 2, 3};
        s.insert(4);
        s.insert("hello");
        mcpy::set_remove(s, 2);
        return s.size();
    }
    """
    assert_code_contains(cpp, expected)


def test_set_to_any_conversion():
    """测试 set -> Any 转换"""

    def test_set_to_any() -> int:
        """set -> Any 转换"""
        s: set[int] = {1, 2, 3}
        x: Any = s
        s2: set[int] = x
        return len(s2)

    cpp = compile_chunk(test_set_to_any)
    expected = """
    int test_set_to_any() {
        mcpy::variant_set s = {1, 2, 3};
        mc::variant x = s;
        mcpy::variant_set s2 = mcpy::cast<mcpy::variant_set>(x);
        return s2.size();
    }
    """
    assert_code_contains(cpp, expected)


def test_set_any_constructor():
    """测试 set[Any] 的构造函数"""

    def test_constructor() -> int:
        """set[Any] 构造"""
        # 从 list[Any] 构造 set[Any]
        numbers: list[Any] = [1, 2, 2, 3, 3, 3]
        unique: set[Any] = set(numbers)
        return len(unique)

    cpp = compile_chunk(test_constructor)
    expected = """
    int test_constructor() {
        mc::variants numbers = {1, 2, 2, 3, 3, 3};
        mcpy::variant_set   unique  = mcpy::set_construct<mc::variant>(numbers);
        return unique.size();
    }
    """
    assert_code_contains(cpp, expected)


def test_set_any_union_operation():
    """测试 set[Any] 的并集运算"""

    def test_union() -> int:
        """set[Any] 并集"""
        s1: set[Any] = {1, 2, 3}
        s2: set[Any] = {3, 4, 5}
        result: set[Any] = s1 | s2
        return len(result)

    cpp = compile_chunk(test_union)
    expected = """
    int test_union() {
        mcpy::variant_set s1     = {1, 2, 3};
        mcpy::variant_set s2     = {3, 4, 5};
        mcpy::variant_set result = mcpy::set_union(s1, s2);
        return result.size();
    }
    """
    assert_code_contains(cpp, expected)


def test_set_any_in_dict():
    """测试 set[Any] 存储在 dict 中"""

    def test_in_dict() -> int:
        """set 在 dict 中"""
        data: dict = {"items": {1, 2, 3}}
        items: set[Any] = data["items"]
        return len(items)

    cpp = compile_chunk(test_in_dict)
    expected = """
    int test_in_dict() {
        mc::dict               data  = mc::dict{{"items", mcpy::variant_set{1, 2, 3}}};
        mcpy::variant_set items = mcpy::cast<mcpy::variant_set>(data["items"]);
        return items.size();
    }
    """
    assert_code_contains(cpp, expected)


def test_set_any_iteration():
    """测试 set[Any] 的迭代"""

    def test_iteration() -> int:
        """set[Any] 迭代"""
        numbers: set[Any] = {1, 2, 3, 4, 5}
        total: Any = 0
        for x in numbers:
            total = total + x
        result: int = total
        return result

    cpp = compile_chunk(test_iteration)
    expected = """
    int test_iteration() {
        mcpy::variant_set numbers = {1, 2, 3, 4, 5};
        mc::variant            total   = 0;
        for (const auto& x : numbers) {
            total = total + x;
        }
        int result = mcpy::cast<int>(total);
        return result;
    }
    """
    assert_code_contains(cpp, expected)


def test_set_any_comprehension():
    """测试 set[Any] 推导式"""

    def test_comprehension() -> int:
        """set[Any] 推导式"""
        numbers: list[Any] = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
        unique: set[Any] = {x for x in numbers}
        return len(unique)

    cpp = compile_chunk(test_comprehension)
    expected = """
    int test_comprehension() {
        mc::variants numbers = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4};
        mcpy::variant_set unique = mcpy::set_comprehension(numbers, [&](const auto& x) {
            return x;
        });
        return unique.size();
    }
    """
    assert_code_contains(cpp, expected)


def test_set_any_contains():
    """测试 set[Any] 的 in 运算符"""

    def test_contains() -> bool:
        """set[Any] contains"""
        items: set[Any] = {42, "hello", 3.14}
        return 42 in items and "hello" in items

    cpp = compile_chunk(test_contains)
    expected = """
    bool test_contains() {
        mcpy::variant_set items = {42, "hello", 3.14};
        return mcpy::set_contains(items, 42) && mcpy::set_contains(items, "hello");
    }
    """
    assert_code_contains(cpp, expected)


def test_any_to_set_direct_conversion():
    """测试 Any -> set 的直接转换（无需中间变量）"""

    def test_direct() -> int:
        """直接转换 len(set(a))"""
        a: Any = {1, 2, 3}
        # 直接转换，无需中间变量
        return len(set(a))

    cpp = compile_chunk(test_direct)
    expected = """
    int test_direct() {
        mc::variant a = mcpy::variant_set{1, 2, 3};
        return mcpy::set_from_any<{T}>(a).size();
    }
    """
    assert_code_contains(cpp, expected)


def test_any_to_set_comparison():
    """测试两种转换方式的对比"""

    def test_comparison() -> int:
        """对比传统方式和直接转换"""
        a: Any = {1, 2, 3}
        # 传统方式：需要中间变量
        s: set[int] = a
        size1: int = len(s)
        # 直接转换：无需中间变量
        size2: int = len(set(a))
        return size1 + size2

    cpp = compile_chunk(test_comparison)
    expected = """
    int test_comparison() {
        mc::variant    a     = mcpy::variant_set{1, 2, 3};
        mcpy::variant_set s     = mcpy::cast<mcpy::variant_set>(a);
        int            size1 = s.size();
        int            size2 = mcpy::set_from_any<{T}>(a).size();
        return size1 + size2;
    }
    """
    assert_code_contains(cpp, expected)
